package gin

import (
	"log"
	"os"
	"time"
)

func ErrorLogger() HandlerFunc {
	return func(c *Context) {
		// 继续执行后续处理函数
		c.Next()

		// 如果错误列表中有信息,则以JSON格式返回给客户端这些信息
		if len(c.Errors) > 0 {
			// -1 是为了不重复设置响应状态码
			c.JSON(-1, c.Errors)
		}
	}
}

var (
	green  = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
	white  = string([]byte{27, 91, 57, 48, 59, 52, 55, 109})
	yellow = string([]byte{27, 91, 57, 55, 59, 52, 51, 109})
	red    = string([]byte{27, 91, 57, 55, 59, 52, 49, 109})
	reset  = string([]byte{27, 91, 48, 109})
)

// Logger 日志中间件,返回一个符合 gin.HandlerFunc 的函数
func Logger() HandlerFunc {

	// 创建一个标准的日志记录器,日志信息输出到控制台,不使用前缀,不使用任何标志
	// 标志负责控制日志输出的格式和内容,如log.Ltime:在日志信息前添加时间:15:04:05
	stdLogger := log.New(os.Stdout, "", 0)

	return func(c *Context) {
		start := time.Now()
		// Process request
		// 让index计数+1,标记本次已经执行过了,并继续执行后面的处理函数
		c.Next()

		// 尝试从请求头中获取ip
		requester := c.Req.Header.Get("X-Real-IP")
		// 如果没有获取到,则尝试从代理中获取
		if requester == "" {
			requester = c.Req.Header.Get("X-Forwarded-For")
		}
		// 如果依旧没获取到,则使用远程地址
		if requester == "" {
			requester = c.Req.RemoteAddr
		}

		var color string
		code := c.Writer.Status()
		// go中的switch会自带break,匹配到了匹配项,会自动跳出switch
		switch {
		case code >= 200 && code <= 299:
			color = green
		case code >= 300 && code <= 399:
			color = white
		case code >= 400 && code <= 499:
			color = yellow
		default:
			color = red
		}
		end := time.Now()
		// 执行时间
		latency := end.Sub(start)
		stdLogger.Printf("[GIN] %v | %s %3d %s| %12v | %s %4s %s\n",
			end.Format("2006/01/02 - 15:04:05"),
			color, c.Writer.Status(), reset,
			latency,
			requester,
			c.Req.Method, c.Req.URL.Path,
		)
		// 最后统计执行过程中错误信息,将这些错误信息输出到控制台
		if len(c.Errors) > 0 {
			stdLogger.Println(c.Errors.String())
		}
	}
}
